/*
 * Copyright (C) 2013-2019 Argonne National Laboratory, Department of Energy,
 *                    UChicago Argonne, LLC and The HDF Group.
 * All rights reserved.
 *
 * The full copyright notice, including terms governing use, modification,
 * and redistribution, is contained in the COPYING file that can be
 * found at the root of the source code distribution tree.
 */

#ifndef MERCURY_UTIL_ERROR_H
#define MERCURY_UTIL_ERROR_H

#include "mercury_util_config.h"

/* Default error macro */
#ifdef HG_UTIL_HAS_VERBOSE_ERROR
#    include <mercury_log.h>
#    define HG_UTIL_LOG_MASK hg_util_log_mask
/* Log mask will be initialized in init routine */
extern HG_UTIL_PRIVATE unsigned int HG_UTIL_LOG_MASK;
#    define HG_UTIL_LOG_MODULE_NAME "HG Util"
#    define HG_UTIL_LOG_ERROR(...)                                             \
        do {                                                                   \
            if (HG_UTIL_LOG_MASK & HG_LOG_TYPE_ERROR)                          \
                HG_LOG_WRITE_ERROR(HG_UTIL_LOG_MODULE_NAME, __VA_ARGS__);      \
        } while (0)
#    ifdef HG_UTIL_HAS_DEBUG
#        define HG_UTIL_LOG_DEBUG(...)                                         \
            do {                                                               \
                if (HG_UTIL_LOG_MASK & HG_LOG_TYPE_DEBUG)                      \
                    HG_LOG_WRITE_DEBUG(HG_UTIL_LOG_MODULE_NAME, __VA_ARGS__);  \
            } while (0)
#    else
#        define HG_UTIL_LOG_DEBUG(...) (void) 0
#    endif
#    define HG_UTIL_LOG_WARNING(...)                                           \
        do {                                                                   \
            if (HG_UTIL_LOG_MASK & HG_LOG_TYPE_WARNING)                        \
                HG_LOG_WRITE_WARNING(HG_UTIL_LOG_MODULE_NAME, __VA_ARGS__);    \
        } while (0)
#else
#    define HG_UTIL_LOG_ERROR(...)   (void) 0
#    define HG_UTIL_LOG_DEBUG(...)   (void) 0
#    define HG_UTIL_LOG_WARNING(...) (void) 0
#endif

/* Branch predictor hints */
#ifndef _WIN32
#    define likely(x)   __builtin_expect(!!(x), 1)
#    define unlikely(x) __builtin_expect(!!(x), 0)
#else
#    define likely(x)   (x)
#    define unlikely(x) (x)
#endif

/* Error macros */
#define HG_UTIL_GOTO_DONE(label, ret, ret_val)                                 \
    do {                                                                       \
        ret = ret_val;                                                         \
        goto label;                                                            \
    } while (0)

#define HG_UTIL_GOTO_ERROR(label, ret, err_val, ...)                           \
    do {                                                                       \
        HG_UTIL_LOG_ERROR(__VA_ARGS__);                                        \
        ret = err_val;                                                         \
        goto label;                                                            \
    } while (0)

/* Check for cond, set ret to err_val and goto label */
#define HG_UTIL_CHECK_ERROR(cond, label, ret, err_val, ...)                    \
    do {                                                                       \
        if (unlikely(cond)) {                                                  \
            HG_UTIL_LOG_ERROR(__VA_ARGS__);                                    \
            ret = err_val;                                                     \
            goto label;                                                        \
        }                                                                      \
    } while (0)

#define HG_UTIL_CHECK_ERROR_NORET(cond, label, ...)                            \
    do {                                                                       \
        if (unlikely(cond)) {                                                  \
            HG_UTIL_LOG_ERROR(__VA_ARGS__);                                    \
            goto label;                                                        \
        }                                                                      \
    } while (0)

#define HG_UTIL_CHECK_ERROR_DONE(cond, ...)                                    \
    do {                                                                       \
        if (unlikely(cond)) {                                                  \
            HG_UTIL_LOG_ERROR(__VA_ARGS__);                                    \
        }                                                                      \
    } while (0)

/* Check for cond and print warning */
#define HG_UTIL_CHECK_WARNING(cond, ...)                                       \
    do {                                                                       \
        if (unlikely(cond)) {                                                  \
            HG_UTIL_LOG_WARNING(__VA_ARGS__);                                  \
        }                                                                      \
    } while (0)

#endif /* MERCURY_UTIL_ERROR_H */
